/// @file Cache.cpp
/// @brief stores and export positions of fluid and rbd to file

#include "Cache.h"
#include <fstream>
#include <QString>

Cache::Cache()
{

}

void Cache::addItem(const CacheItem& _cacheItem)
{
    m_fluidCache.push_back(_cacheItem);
}

void Cache::flushCache(const std::string _path)
{
    //loop through cache items
    for (int i = 0; i < m_fluidCache.size(); ++i)
    {
        //get cache item
        CacheItem item = m_fluidCache[i];

        //loop through name list of the item
        for (int j = 0; j < item.getNameList().size(); ++j)
        {
            //determine type of item
            std::string itemType;
            if (item.getCacheItemType() == FLUID_CACHE)
                itemType = "Fluid";
            else if (item.getCacheItemType() == BOUNDARY_CACHE)
                itemType = "Boundary";
            else if (item.getCacheItemType() == SPHERE_CACHE)
                itemType = "Sphere";
            else if (item.getCacheItemType() == CAPSULE_CACHE)
                itemType = "Capsule";
            else
                itemType = "NA";

            //construct filename of the item for the current frame number
            QString text = QString("%1%2_%3_Frame_%4.geo")
                            .arg(_path.c_str())
                            .arg(itemType.c_str())
                            .arg(std::string(item.getNameList()[j]).c_str())
                            .arg(item.getFrameNumber());

            //write data to file
            if (item.getCacheItemType() == FLUID_CACHE || item.getCacheItemType() == SPHERE_CACHE || item.getCacheItemType() == CAPSULE_CACHE)
                writePointData(item.getPositionList()[j], text.toStdString());
            else if (item.getCacheItemType() == BOUNDARY_CACHE)
                writeBoundaryData(item.getPositionList()[j], text.toStdString());

        }
    }

    //clear cache
    m_fluidCache.clear();
}

void Cache::writePointData
                (
                    std::vector<ngl::Vector>& _positionList,
                    const std::string& _filename
                )
{
    //open file for writing
    std::ofstream outFile(_filename.c_str(), std::ios::out);

    //write header
    outFile << "PGEOMETRY V5\n";
    outFile << "NPoints " << _positionList.size() << " NPrims 0\n";
    outFile << "NPointGroups 0 NPrimGroups 0\n";
    outFile << "NPointAttrib 0 NVertexAttrib 0 NPrimAttrib 0 NAttrib 0\n";

    //loop through position list
    for (int i = 0; i < _positionList.size(); ++i)
    {
        outFile
                << _positionList[i].m_x << " "
                << _positionList[i].m_y << " "
                << _positionList[i].m_z << " "
                << _positionList[i].m_w << "\n";
    }

    //write the outro
    outFile << "beginExtra\n";
    outFile << "endExtra";

    //close file
    outFile.close();
}

void Cache::writeBoundaryData
                (
                    std::vector<ngl::Vector>& _positionList,
                    const std::string& _filename
                )
{
    //open file for writing
    std::ofstream outFile(_filename.c_str(), std::ios::out);

    //write header
    outFile << "PGEOMETRY V5\n";
    outFile << "NPoints 8 NPrims 6\n";
    outFile << "NPointGroups 0 NPrimGroups 0\n";
    outFile << "NPointAttrib 0 NVertexAttrib 0 NPrimAttrib 0 NAttrib 0\n";

    //loop through position list
    for (int i = 0; i < _positionList.size(); ++i)
    {
        outFile
                << _positionList[i].m_x << " "
                << _positionList[i].m_y << " "
                << _positionList[i].m_z << " "
                << _positionList[i].m_w << "\n";
    }

    //write box vertex connections
    outFile << "Run 6 Poly\n";
    outFile << " 4 < 1 5 4 0\n";
    outFile << " 4 < 2 6 5 1\n";
    outFile << " 4 < 3 7 6 2\n";
    outFile << " 4 < 0 4 7 3\n";
    outFile << " 4 < 2 1 0 3\n";
    outFile << " 4 < 5 6 7 4\n";

    //write the outro
    outFile << "beginExtra\n";
    outFile << "endExtra";

    //close file
    outFile.close();
}
